package main

import (
	"encoding/hex"
	"encoding/json"
	"goqk/blockchain"
	"goqk/pki/manager"
	"goqk/consensus/pow"
	"goqk/core/crytography"
	"goqk/core/events"
	"goqk/core/gossip"
	io "goqk/core/io"
	"goqk/core/p2p"
	crest "goqk/core/rest"
	"goqk/core/tree"
	"goqk/excitation"
	conf "goqk/node/config"
	"goqk/node/rest"
	"log"
	"os"
	"time"
)

var (
	synChan = make(chan int)
	// serviceName  = "LedgerService"
	ledger       blockchain.Ledger
	queryServer  blockchain.QueryServer
	consensus    pow.Pow
	p2pServer    p2p.Server
	beltline     excitation.CoinBeltline
	nodeRest     rest.NodeServer
	cm           manager.CertificateManager
	km           manager.KeyManager
	nodeID       string
	gBlockServer gossip.Gossiper
	gTranServer  gossip.Gossiper
)

func main() {
	// 加载配置
	loadConfig()
	// 注册
	registryNode()
	// 同步世界数据(区块)
	go gBlockServer.Run(conf.Config.GossipBlockMembers, conf.Config.GossipBlockServerPort, synChan)
	// 同步世界数据(交易)
	go gTranServer.Run(conf.Config.GossipTransactionMembers, conf.Config.GossipTransactionServerPort, nil)
	// 初始化账本
	initLedger()
	// 启动本地交易服务器
	go nodeRest.Run()
	// 启动本地区块信息查询服务
	go queryServer.Run(&ledger)
	// 初始化共识
	consensus.Intialize(1, nodeID, &ledger, &beltline, &gBlockServer, &gTranServer)
	// 追加其他节点生成的区块
	events.Subscribe("Gossiper", "b", func(e events.Event) {
		go consensus.Append()
	})
	// 开始记账
	go consensus.Work()
	// 阻塞
	select {}
}

func loadConfig() {
	// 加载配置文件
	var err error
	conf.Config, err = conf.LoadNodeConfig()
	blockchain.Config, err = conf.LoadLedgerConfig()
	// p2p.Config, err = conf.LoadP2PServerConfig()
	tree.Config, err = conf.LoadTreeConfig()
	if err != nil {
		log.Fatal(err)
	}
	// consensus.ServiceName = serviceName
	log.Println("已经加载配置文件.")
}

func initLedger() {
	if conf.Config.GossipBlockMembers != "" {
		return
	}
	// 如果没有数据，则创建创世块
	genesisBlock := blockchain.Block{}
	genesisBlock.Header = blockchain.BlockHeader{
		Index:      1,
		Version:    0x01,
		Nonce:      1,
		Timestamp:  time.Now().String(),
		PrevHash:   "",
		MerkleRoot: "",
		Hash:       consensus.CalculateHash(&genesisBlock)}
	genesisBlock.Body = blockchain.BlockBody{}

	ledger = blockchain.Ledger{CurBlock: genesisBlock}
	// 发布创世块，等待gossip运行起来
	<-synChan
	close(synChan)
	data, _ := blockchain.MarshalBlock(genesisBlock)
	b := blockchain.UnmarshalBlock(data)
	log.Println(b.Header.Hash)
	gBlockServer.Add(genesisBlock.Header.Hash, data, "d")
	// ledger.Persistence()
	log.Println("创建创世块")
}

func registryNode() {
	// 没有秘钥，生成秘钥对
	if _, err := os.Stat(conf.Config.PrivateKeyPath); os.IsNotExist(err) {
		km.GenerateKeyFile("123456", conf.Config.PrivateKeyPath, conf.Config.PublicKeyPath)
		log.Println("已生成节点秘钥文件.")
	}

	// 用公钥生成NodeID
	data, err := io.ReadAll(conf.Config.PublicKeyPath)
	if err == nil {
		nodeID = crytography.Hash(data)
		log.Println("已生成nodeID:" + nodeID)
	}

	if _, err := os.Stat(conf.Config.CAPubKeyPath); os.IsNotExist(err) {
		// 下载身份管理机构公钥文件
		if keydata, err := crest.Get(conf.Config.CAServerAddress + "/get_public_key"); err == nil {
			io.WriteFile(conf.Config.CAPubKeyPath, keydata)
			log.Println("已获取到CA服务证书文件.")
		}
	}

	if _, err := os.Stat(conf.Config.CertPath); os.IsNotExist(err) {
		// 生成证书文件
		if keydata, err := json.Marshal(manager.Message{CommonName: "", Organization: "", PubKeyData: hex.EncodeToString(data)}); err == nil {
			if certdata, err := crest.PostJSON(conf.Config.CAServerAddress+"/check_cert", keydata); err != nil {
				io.WriteFile(conf.Config.CertPath, certdata)
				log.Println("已生成节点证书文件.")
			}
		}
	}
}
